﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.Diagnostics;
using Microsoft.Xna.Framework.Input;

namespace StarControl
{
    /// <summary>
    /// <para> O golpe especial de uma das naves deve, necessariamente, </para>
    /// <para> ser um míssil teleguiado (através do steering behavior pursuit); </para>
    /// <para> O míssil teleguiado fica um tempo pré-definido na tela.</para>
    /// <para> A explosão do míssil deve atingir também a nave que o atirou, caso seja muito próxima. </para>
    /// </summary>
    public class MissilTeleguiado : Arma
    {


        private const float TEMPO_MAX_VIDA_MISSIL = 10;
        private const int  VALOR_DANO = 5;
        private const int  NAVE_MILLENIUM = 1;
        private const int  NAVE_PEGASUS = 2;
        private const int  NAVE_VALKYRIE = 3;       

        public static Vector2 posMouse;
        //private Texture2D imagem;
        private float tempoInicioMissel;
        private float massa;
        private float maxForca;
        private float angulo = 0.0f;
        private PersuitBehavior persuit;
        private WanderBehavior wander;
        private FleeBehavior flee;
        private Nave Owner;

        private bool missilAlive;
        private Nave naveAlvo;
        private List<God> listaObjetosColididos; //obstaculos(asteroides) e naves com o qual ocorreu colisão.
        private int comportamento;

        float orientacao;

        public MissilTeleguiado(Game game, Nave owner, Vector2 posicao, float orientacao, float massa, float maxVelocidade,
            float maxForca, Nave naveAlvo) : base(game, new Vector2(), posicao, maxVelocidade)
        {
            posMouse = new Vector2();
            this.Owner = owner;
            this.massa = massa;
            this.maxForca = maxForca;
            this.setDirecao(new Vector2((float)Math.Cos(orientacao), (float)Math.Sin(orientacao)));
            this.naveAlvo = naveAlvo;
            this.missilAlive = true;
            listaObjetosColididos = new List<God>();
        }

        public Nave getOwner()
        {
            return this.Owner;
        }

        public override void Initialize()
        {
            base.Initialize();
            orientacao = 0;
            setImagem(carregarImagem("imagens/missel"));
            travarAlvo(naveAlvo);

            if (naveAlvo is MileniumFalconShip)
            {
                comportamento = NAVE_MILLENIUM;

            }else 
                if (naveAlvo is PegasusShip)
                 {
                    comportamento = NAVE_PEGASUS;
                 }
                else
                    if(naveAlvo is ValkyrieShip)
                    {
                        comportamento = NAVE_VALKYRIE;
                    }

        }

        /// <summary>
        /// <para>Checa se o míssil deve desabilitado/sumir da tela.</para> 
        /// <para>O míssil deve morrer se ele não está mais dentro do tempo de vida dele e/ou </para>
        /// <para>se ocorreu colisão contra a nave.</para>
        /// <para>Caso uma das opções seja verdadeira, retorna False, ou seja, o míssil deve ser desabilitado.</para>
        /// </summary>
        /// <param name="gameTime"></param>
        /// <returns></returns>
        private bool isMissilAlive(GameTime gameTime)
        {
            if (tempoInicioMissel == 0)
            {
                tempoInicioMissel = (float)gameTime.TotalGameTime.TotalSeconds;
            }

            float tempoVidaMissel = (float)gameTime.TotalGameTime.TotalSeconds - tempoInicioMissel;
            bool colisao = naveAlvo.ocorreuColisao(getImagem(), getPosition());

            if (tempoVidaMissel > TEMPO_MAX_VIDA_MISSIL || colisao)
            {
                listaObjetosColididos.Add(naveAlvo);
                //return false;
            }

            List<Obstaculo> listaObstaculos = recuperaComponentes<Obstaculo>();
            foreach (Obstaculo obstaculo in listaObstaculos)
            {
                if (obstaculo.ocorreuColisao(getImagem(), getPosition()))
                {
                    listaObjetosColididos.Add(obstaculo);
                    //return false;
                }
            }

            //houve colisão com algum tipo de objeto
            if (listaObjetosColididos.Count > 0)
            {
                return false;
            }

            return true;

        }


        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
            float secs = (float)gameTime.ElapsedGameTime.TotalSeconds;
            Vector2 posAntes = getPosition();


            //Se o missil deve morrer por tempo excedido ou porque atingiu o alvo
            // não são feitos mais os calculos abaixo
            if (isMissilAlive(gameTime))
            {

                Vector2 steering_force = new Vector2();
                bool comportamentoPadrao = true;

                // se for nave com escudo
                if (naveAlvo is MileniumFalconShip){
                    MileniumFalconShip nave = (MileniumFalconShip) naveAlvo;

                    // se em modo invísil, fica em wander
                    if (nave.isEscudoAtivo())
                    {
                        steering_force = wander.calculateWanderMissil(this, secs);
                        comportamentoPadrao = false;
                    }

                }else

                    // se for nave com flare
                    if (naveAlvo is PegasusShip)
                    {
                        PegasusShip nave = (PegasusShip)naveAlvo;
                        // se em modo invísil, fica em flee
                        if (nave.isEscudoAtivo())
                        {
                            Vector2 pos = naveAlvo.getEscudo().getPosition();
                            steering_force = flee.Calculate(this, secs, pos);
                            comportamentoPadrao = false;
                        }


                    }else
                        // se for nave com *****
                        if(comportamento == NAVE_VALKYRIE){
                            // se em modo *****, fica em *****
                           // steering_force = flee.CalcularPersuit(this, secs);
                            //comportamentoPadrao = false;
                        }

                // se em modo normal, persegue
                if (comportamentoPadrao)
                {
                    steering_force = persuit.CalcularPersuit(this, secs);
                }

                if (steering_force.Length() > maxForca)
                {
                    steering_force.Normalize();
                    steering_force *= maxForca;
                }
                steering_force *= secs;

                Vector2 acceleration = steering_force / massa;

                velocidade += acceleration;
                if (velocidade.Length() > getMaxVelocidade())
                {
                    velocidade.Normalize();
                    velocidade *= getMaxVelocidade();
                }

                //Calcula a nova direção
                if (velocidade.Length() < 0.001)
                {
                    velocidade = new Vector2();
                }
                else
                {
                    this.setDirecao(Vector2.Normalize(velocidade));
                }

                float radiano = MathHelper.ToRadians(angulo);
                this.setDirecao(new Vector2((float)Math.Cos(radiano), (float)Math.Sin(radiano)));

                setPosition(getPosition() + velocidade * secs);

                // Verificando a orientacao da flecha
                orientacao = (float)Math.Atan2(getPosition().Y - posAntes.Y,
                    getPosition().X - posAntes.X);

                //Circula pela tela
                int w = 800;
                int h = 600;

                int missilw = getImagem().Width;
                int missilh = getImagem().Height;

                Vector2 posicaoAux = getPosition();

                if (getPosition().X < -missilw)
                {
                    posicaoAux.X = w + missilw - 1;
                }
                else if (getPosition().X > w + missilw)
                {
                    posicaoAux.X = -missilw + 1;
                }

                if (getPosition().Y < -missilh)
                {
                    posicaoAux.Y = h + missilh - 1;
                }
                else
                    if (getPosition().Y > h + missilh)
                    {
                        posicaoAux.Y = -missilh + 1;
                    }
                setPosition(posicaoAux);
            }
            else
            {
                if (missilAlive)
                {
                    naveAlvo.descontarDano(VALOR_DANO);
                }
                missilAlive = false;
            }
        }


        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);
            //Testa se o missil ainda deve aparecer em tela.
            if (missilAlive)
            {
                getBatch().Begin();

                /*
                getBatch().Draw(getImagem(), getPosition(), null, Color.White, (float)Math.Atan2(getDirecao().Y, getDirecao().X),
                    new Vector2(getImagem().Width / 2, getImagem().Height / 2), 1.0f, SpriteEffects.None, 0.0f);
                */
                getBatch().Draw(getImagem(), getPosition(), null, Color.White, orientacao,
                    new Vector2(getImagem().Width / 2, getImagem().Height / 2), 1.0f, SpriteEffects.FlipHorizontally, 0.0f);
                
                getBatch().End();
            }
        }

        public void travarAlvo(Nave naveAlvo)
        {
            persuit = new PersuitBehavior(naveAlvo);

            wander = new WanderBehavior(50, new Random().Next(20, 180), 100);

            flee =  new FleeBehavior();

        }

        public override bool ocorreuColisaoArma()
        {
            return false;
        }
              
    }
}
